package com.marketing.auth.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.marketing.auth.dto.LoginRequest;
import com.marketing.auth.dto.LoginResponse;
import com.marketing.auth.dto.UserInfoDto;
import com.marketing.auth.dto.UserPermissionDto;
import com.marketing.auth.entity.User;
import com.marketing.auth.mapper.UserMapper;
import com.marketing.auth.service.RbacService;
import com.marketing.auth.service.TokenService;
import com.marketing.auth.service.UserService;
import com.marketing.auth.util.JwtUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 用户服务实现类
 */
@Service
public class UserServiceImpl implements UserService {

    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private JwtUtil jwtUtil;
    
    @Autowired
    private UserMapper userMapper;
    
    @Autowired
    private TokenService tokenService;
    
    @Autowired
    private RbacService rbacService;
    
    @Value("${server.port}")
    private int serverPort;
    
    // BCrypt密码加密器
    private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    @Override
    public LoginResponse login(LoginRequest loginRequest) {
        logger.info("开始用户登录验证，用户名: {}", loginRequest.getUsername());
        
        try {
            // 1. 验证输入参数
            if (loginRequest.getUsername() == null || loginRequest.getPassword() == null) {
                logger.warn("登录失败：用户名或密码为空，用户名: {}", loginRequest.getUsername());
                return new LoginResponse(false, "用户名和密码不能为空");
            }
            logger.debug("参数验证通过，用户名: {}", loginRequest.getUsername());

            // 2. 查找用户
            logger.debug("查找用户信息，用户名: {}", loginRequest.getUsername());
            User user = findByUsername(loginRequest.getUsername());
            if (user == null) {
                logger.warn("登录失败：用户不存在，用户名: {}", loginRequest.getUsername());
                return new LoginResponse(false, "用户不存在");
            }
            logger.debug("用户信息查找成功，用户ID: {}, 用户名: {}, 状态: {}", user.getId(), user.getUsername(), user.getStatus());

            // 3. 验证用户状态
            if (user.getStatus() == null || user.getStatus() != 1) {
                logger.warn("登录失败：用户账号已被禁用，用户名: {}, 状态: {}", loginRequest.getUsername(), user.getStatus());
                return new LoginResponse(false, "用户账号已被禁用");
            }
            logger.debug("用户状态正常，用户名: {}", loginRequest.getUsername());

            // 4. 验证密码
            logger.debug("开始验证密码，用户名: {}", loginRequest.getUsername());
            if (!validatePassword(loginRequest.getPassword(), user.getPassword())) {
                logger.warn("登录失败：密码错误，用户名: {}", loginRequest.getUsername());
                return new LoginResponse(false, "密码错误");
            }
            logger.debug("密码验证通过，用户名: {}", loginRequest.getUsername());

            // 5. 获取用户完整权限信息（用于生成Token）
            UserPermissionDto userPermissionDto = rbacService.getUserPermissionInfo(user.getId());
            logger.debug("用户权限信息获取成功，用户名: {}, 角色数量: {}, 权限数量: {}", 
                    loginRequest.getUsername(), 
                    userPermissionDto.getRoles() != null ? userPermissionDto.getRoles().size() : 0,
                    userPermissionDto.getPermissions() != null ? userPermissionDto.getPermissions().size() : 0);
            
            // 5.1 准备Token中的权限数据
            List<String> roleCodes = userPermissionDto.getRoles() != null 
                    ? userPermissionDto.getRoles().stream().map(roleDto -> roleDto.getRoleCode()).collect(java.util.stream.Collectors.toList())
                    : new ArrayList<>();
            Set<String> permissionCodes = userPermissionDto.getPermissionCodes() != null 
                    ? userPermissionDto.getPermissionCodes() 
                    : new HashSet<>();
            
            // 5.2 生成包含权限信息的JWT Token
            logger.debug("开始生成包含权限信息的JWT Token，用户名: {}, 用户ID: {}, 主要角色: {}, 角色数量: {}, 权限数量: {}", 
                    loginRequest.getUsername(), user.getId(), userPermissionDto.getRole(), roleCodes.size(), permissionCodes.size());
            String token = jwtUtil.generateTokenWithPermissions(
                    user.getUsername(), 
                    user.getId(), 
                    userPermissionDto.getRole(),
                    roleCodes,
                    permissionCodes
            );
            logger.debug("包含权限信息的JWT Token生成成功，用户名: {}, Token长度: {}", loginRequest.getUsername(), token.length());
            
            // 6. 创建UserInfoDto（基础版本）
            UserInfoDto userInfoDto = convertToUserInfoDto(user);
            logger.debug("用户信息DTO创建成功，用户名: {}", loginRequest.getUsername());
            
            // 6.1 将基础用户信息复制到权限DTO中
            
            // 7. 将Token存储到Redis（存储完整权限信息）
            logger.debug("开始存储Token到Redis，用户名: {}, 过期时间: {}秒", loginRequest.getUsername(), jwtUtil.getExpirationTimeInSeconds());
            tokenService.storeToken(token, userInfoDto, jwtUtil.getExpirationTimeInSeconds());
            logger.info("Token存储到Redis成功，用户名: {}", loginRequest.getUsername());
            
            // 8. 更新最后登录时间
            logger.debug("开始更新最后登录时间，用户名: {}", loginRequest.getUsername());
            updateLastLoginTime(user.getUsername());
            logger.debug("最后登录时间更新成功，用户名: {}", loginRequest.getUsername());

            // 9. 返回登录成功响应（包含权限信息）
            LoginResponse response = new LoginResponse(
                    true, 
                    "登录成功", 
                    token, 
                    jwtUtil.getExpirationTimeInSeconds(), 
                    userPermissionDto,  // 返回完整的权限信息
                    serverPort
            );
            
            logger.info("用户登录成功，用户名: {}, 用户ID: {}, 角色: {}, 权限数量: {}, 服务端口: {}", 
                    loginRequest.getUsername(), user.getId(), 
                    userPermissionDto.getRole(),
                    userPermissionDto.getPermissionCodes() != null ? userPermissionDto.getPermissionCodes().size() : 0,
                    serverPort);
            return response;

        } catch (Exception e) {
            logger.error("用户登录过程中发生异常，用户名: {}, 异常: {}", loginRequest.getUsername(), e.getMessage(), e);
            return new LoginResponse(false, "登录过程中发生错误: " + e.getMessage());
        }
    }

    @Override
    public User findByUsername(String username) {
        logger.debug("查找用户，用户名: {}", username);
        
        try {
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getUsername, username);
            User user = userMapper.selectOne(queryWrapper);
            
            if (user != null) {
                logger.debug("用户查找成功，用户名: {}, 用户ID: {}, 状态: {}", username, user.getId(), user.getStatus());
            } else {
                logger.debug("用户不存在，用户名: {}", username);
            }
            
            return user;
        } catch (Exception e) {
            logger.error("查找用户时发生异常，用户名: {}, 异常: {}", username, e.getMessage(), e);
            return null;
        }
    }

    @Override
    public boolean validatePassword(String rawPassword, String encodedPassword) {
        logger.debug("开始验证密码");
        
        try {
            // 使用BCrypt验证密码
            boolean isValid = passwordEncoder.matches(rawPassword, encodedPassword);
            
            if (isValid) {
                logger.debug("密码验证成功");
            } else {
                logger.debug("密码验证失败");
            }
            
            return isValid;
        } catch (Exception e) {
            logger.error("密码验证过程中发生异常: {}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public void updateLastLoginTime(String username) {
        logger.debug("开始更新用户最后登录时间，用户名: {}", username);
        
        try {
            LocalDateTime now = LocalDateTime.now();
            String clientIp = getClientIpAddress();
            
            // 使用MyBatis-Plus更新用户最后登录信息
            userMapper.updateLastLoginInfo(
                username, 
                now, 
                clientIp,
                now
            );
            
            logger.debug("用户最后登录信息更新成功，用户名: {}, 登录时间: {}, IP: {}", username, now, clientIp);
        } catch (Exception e) {
            logger.error("更新用户最后登录时间失败，用户名: {}, 异常: {}", username, e.getMessage(), e);
        }
    }
    
    /**
     * 加密密码工具方法
     */
    public String encodePassword(String rawPassword) {
        logger.debug("开始加密密码");
        
        try {
            String encoded = passwordEncoder.encode(rawPassword);
            logger.debug("密码加密成功");
            return encoded;
        } catch (Exception e) {
            logger.error("密码加密失败: {}", e.getMessage(), e);
            throw new RuntimeException("密码加密失败", e);
        }
    }
        
    /**
     * 获取客户端IP地址（简化版本）
     */
    private String getClientIpAddress() {
        // 实际项目中可以今HttpServletRequest中获取真实IP
        return "127.0.0.1";
    }
    
    /**
     * 将User对象转换为UserInfoDto
     */
    private UserInfoDto convertToUserInfoDto(User user) {
        logger.debug("开始转换User对象为UserInfoDto，用户ID: {}", user.getId());
        
        try {
            UserInfoDto dto = new UserInfoDto();
            dto.setId(user.getId());
            dto.setUsername(user.getUsername());
            dto.setEmail(user.getEmail());
            dto.setNickname(user.getNickname());
            dto.setAvatar(user.getAvatar());
            dto.setPhone(user.getPhone());
            dto.setStatus(user.getStatus());
            dto.setRole(user.getRole());
            dto.setDepartment(user.getDepartment());
            dto.setPosition(user.getPosition());
            dto.setLoginCount(user.getLoginCount());
            
            logger.debug("User对象转换成功，用户ID: {}, 用户名: {}", user.getId(), user.getUsername());
            return dto;
        } catch (Exception e) {
            logger.error("User对象转换失败，用户ID: {}, 异常: {}", user.getId(), e.getMessage(), e);
            throw new RuntimeException("User对象转换失败", e);
        }
    }
    
    /**
     * 将基础用户信息复制到权限DTO中
     */
    private void copyUserInfoToPermissionDto(UserInfoDto userInfo, UserPermissionDto permissionDto) {
        permissionDto.setId(userInfo.getId());
        permissionDto.setUsername(userInfo.getUsername());
        permissionDto.setEmail(userInfo.getEmail());
        permissionDto.setNickname(userInfo.getNickname());
        permissionDto.setAvatar(userInfo.getAvatar());
        permissionDto.setPhone(userInfo.getPhone());
        permissionDto.setStatus(userInfo.getStatus());
        permissionDto.setDepartment(userInfo.getDepartment());
        permissionDto.setPosition(userInfo.getPosition());
        permissionDto.setLoginCount(userInfo.getLoginCount());
    }
}